/** 
  Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.<BR>
  SPDX-License-Identifier: BSD-2-Clause-Patent


Module Name:

  SaveMemoryConfig.c

Abstract:
  This is the driver that locates the MemoryConfigurationData HOB, if it
  exists, and saves the data to nvRAM.

 

--*/

#include "SaveMemoryConfig.h"

CHAR16    EfiMemoryConfigVariable[] = L"MemoryConfig";


EFI_STATUS
EFIAPI
SaveMemoryConfigEntryPoint (
  IN EFI_HANDLE         ImageHandle,
  IN EFI_SYSTEM_TABLE   *SystemTable
  )
/*++

  Routine Description:
    This is the standard EFI driver point that detects whether there is a
    MemoryConfigurationData HOB and, if so, saves its data to nvRAM.

  Arguments:
    ImageHandle   - Handle for the image of this driver
    SystemTable   - Pointer to the EFI System Table

  Returns:
    EFI_SUCCESS   - if the data is successfully saved or there was no data
    EFI_NOT_FOUND - if the HOB list could not be located.
    EFI_UNLOAD_IMAGE - It is not success

--*/
{
  EFI_STATUS                      Status=EFI_SUCCESS;
  VOID                            *MemHobData;
  VOID                            *VariableData;
  UINTN                           BufferSize;
  BOOLEAN                         MfgMode;
  EFI_PLATFORM_SETUP_ID           *BootModeBuffer;
  EFI_PLATFORM_INFO_HOB           *PlatformInfoHobPtr;
  MEM_INFO_PROTOCOL               *MemInfoProtocol;
  EFI_HANDLE                      Handle;
  UINT8							              Channel, Slot;
  VOID                            *GuidHob;

  VariableData   = NULL;
  MfgMode        = FALSE;
  Handle         = NULL;
  BootModeBuffer = NULL;
  MemHobData     = NULL;
  PlatformInfoHobPtr = NULL;
  BufferSize     = 0;

  //
  // Get Platform Info HOB
  //
  GuidHob = GetFirstGuidHob (&gEfiPlatformInfoGuid);
  if (GuidHob == NULL) {
    Status = EFI_NOT_FOUND;
  }
  ASSERT_EFI_ERROR (Status);

  PlatformInfoHobPtr = GET_GUID_HOB_DATA (GuidHob);

  //
  // Get the BootMode guid hob
  //
  GuidHob = GetFirstGuidHob (&gEfiPlatformBootModeGuid);
  if (GuidHob == NULL) {
    Status = EFI_NOT_FOUND;
  }
  ASSERT_EFI_ERROR (Status);

  BootModeBuffer = GET_GUID_HOB_DATA (GuidHob);


  //
  // Check whether in Manufacturing Mode
  //
  if (BootModeBuffer) {
    if ( !CompareMem (   //EfiCompareMem
            &BootModeBuffer->SetupName,
            MANUFACTURE_SETUP_NAME,
            StrSize (MANUFACTURE_SETUP_NAME)  //EfiStrSize
            ) ) {
      MfgMode = TRUE;
    }
  }

  if (MfgMode) {
    //
    // Don't save Memory Configuration in Manufacturing Mode. Clear memory configuration.
    //
    Status = gRT->SetVariable (
              EfiMemoryConfigVariable,
              &gEfiVlv2VariableGuid,
              EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
              0,
              NULL
              );      
  } else {

    MemInfoProtocol = (MEM_INFO_PROTOCOL*)AllocateZeroPool(sizeof(MEM_INFO_PROTOCOL));
    if (PlatformInfoHobPtr != NULL) {
      MemInfoProtocol->MemInfoData.memSize  = 0;
      for (Channel = 0; Channel < CH_NUM; Channel ++){
        for (Slot = 0; Slot < DIMM_NUM; Slot ++){               
          MemInfoProtocol->MemInfoData.dimmSize[Slot + (Channel * DIMM_NUM)] = PlatformInfoHobPtr->MemData.DimmSize[Slot + (Channel * DIMM_NUM)];
        }
      }
  	  MemInfoProtocol->MemInfoData.memSize       = PlatformInfoHobPtr->MemData.MemSize;        
  	  MemInfoProtocol->MemInfoData.EccSupport    = PlatformInfoHobPtr->MemData.EccSupport;
      MemInfoProtocol->MemInfoData.ddrFreq       = PlatformInfoHobPtr->MemData.DdrFreq;
      MemInfoProtocol->MemInfoData.ddrType       = PlatformInfoHobPtr->MemData.DdrType;
      if (MemInfoProtocol->MemInfoData.memSize == 0){
        //
        // We hardcode if MRC didn't fill these info in
        //
        MemInfoProtocol->MemInfoData.memSize     = 0x800; //per 1MB 
        MemInfoProtocol->MemInfoData.dimmSize[0] = 0x800;
        MemInfoProtocol->MemInfoData.dimmSize[1] = 0;    
        MemInfoProtocol->MemInfoData.EccSupport  = FALSE;
        MemInfoProtocol->MemInfoData.ddrType     = 5; //DDRType_LPDDR3
      }

      Status = gBS->InstallMultipleProtocolInterfaces (
             &Handle,
             &gMemInfoProtocolGuid,
             MemInfoProtocol,
             NULL
             );
    }

    Status = EFI_SUCCESS;
    if (BOOT_WITH_MINIMAL_CONFIGURATION != GetBootModeHob()){
      //
      // Get the Memory Config guid hob
      //
      GuidHob = GetFirstGuidHob (&gEfiMemoryConfigDataGuid);
      if (GuidHob == NULL) {
        Status = EFI_NOT_FOUND;
      }
      ASSERT_EFI_ERROR (Status);
      
      MemHobData = GET_GUID_HOB_DATA (GuidHob);
      BufferSize = GET_GUID_HOB_DATA_SIZE (GuidHob);

      Status = gRT->GetVariable (
                  EfiMemoryConfigVariable,
                  &gEfiVlv2VariableGuid,
                  NULL,
                  &BufferSize,
                  VariableData
                  );
      if (EFI_ERROR(Status) && (MemHobData != NULL)) {    
        Status = gRT->SetVariable (
                      EfiMemoryConfigVariable,
                      &gEfiVlv2VariableGuid,
                      (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS),
                      BufferSize,
                      MemHobData
                      );
      } 
    }

  } // if-else MfgMode

  return EFI_SUCCESS;
}
